package com.info.zhiduoduo.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.google.common.collect.Lists;
import com.info.zhiduoduo.common.configs.DingdingNoticeConfig;
import com.info.zhiduoduo.common.configs.NotificationConfig;
import com.info.zhiduoduo.common.utils.ExceptionUtil;
import com.info.zhiduoduo.core.dto.dingdingnotice.DingdingNoticeMsg;
import com.info.zhiduoduo.core.dto.dingdingnotice.GroupCode;
import com.info.zhiduoduo.core.service.DingdingNoticeService;
import com.info.zhiduoduo.repository.entity.notice.DingdingNotice;
import com.info.zhiduoduo.wxsdk.utils.HttpUtil;
import com.info.zhiduoduo.wxsdk.utils.LogUtil;

import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.time.Instant;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class DingdingNoticeServiceImpl implements DingdingNoticeService {

	@Autowired
	DingdingNoticeConfig dingdingNoticeConfig;
	@Autowired
	NotificationConfig notificationConfig;

	private static ExecutorService executor;

	@PostConstruct
	public void init() {
		executor = Executors.newSingleThreadExecutor();
	}

	@PreDestroy
	public void destroy() {
		try {
			executor.shutdown();
			executor.awaitTermination(3000, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
		}
	}

	@Override
	public void sendNotice(GroupCode groupCode, String content) {
		DingdingNotice notice = new DingdingNotice().setType(groupCode.type).setContent(content).setCreatetime(new Date());
		DingdingNoticeMsg msg = DingdingNoticeMsg.of(content, Lists.newArrayList(notificationConfig.getBossPhone()));
		String url = dingdingNoticeConfig.getApiUrl() + dingdingNoticeConfig.getNormalToken();
		LogUtil.info("发送钉钉消息：url=" + url + "\n消息=" + JSON.toJSONString(msg));
		try {
			String s = HttpUtil.postData(url, JSON.toJSONString(msg));
			notice.setResult(s);
		} catch (Exception e) {
			e.printStackTrace();
		}
		notice.insert();
	}

	@Override
	public void sendExceptionMessage(String title, Exception e) {
		if (dingdingNoticeConfig.isExceptionPrinterEnable()) {
			executor.submit(() -> sendExceptionMessageInternal(title, ExceptionUtil.getErrorStackTrace(e)));
		}
	}

	@Override
	public void sendMessage(String title, String message) {
		if (dingdingNoticeConfig.isExceptionPrinterEnable()) {
			executor.submit(() -> sendExceptionMessageInternal(title, message));
		}
	}

	private void sendExceptionMessageInternal(String title, String message) {
		try {
			//获取系统时间戳
			long timestamp = Instant.now().toEpochMilli();
			//拼接
			String stringToSign = timestamp + "\n" + dingdingNoticeConfig.getExceptionPrinterSecret();
			String sign = genSign(dingdingNoticeConfig.getExceptionPrinterSecret(), stringToSign);

			//钉钉机器人地址（配置机器人的webhook）
			String url = String.format(dingdingNoticeConfig.getExceptionPrinterWebhook(), timestamp, sign);
			DingTalkClient client = new DefaultDingTalkClient(url);
			OapiRobotSendRequest request = new OapiRobotSendRequest();
			request.setMsgtype("text");

			OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
			text.setContent(title + "\n" + message);
			request.setText(text);
			OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
			// at.setAtMobiles(Arrays.asList("13162192787"));
			// isAtAll类型如果不为Boolean，请升级至最新SDK
			at.setIsAtAll(false);
			request.setAt(at);
			OapiRobotSendResponse response = client.execute(request);
			if (!response.isSuccess()) {
				log.info("发送钉钉报警消息失败,失败消息:{}", response.getErrmsg());
			}
		} catch (Exception e) {
			log.error("发送钉钉报警消息失败:", e);
		}
	}


	private static String genSign(String secret, String stringToSign) throws Exception {
		//使用HmacSHA256算法计算签名
		Mac mac = Mac.getInstance("HmacSHA256");
		mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
		byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
		//进行Base64 encode 得到最后的sign，可以拼接进url里
		return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
	}
}
